package openase.audiosearch.processor;

import openase.audio.AudioFingerprint;
import openase.audio.StorageException;
import openase.audio.fingerprinthash.FingerprintGeneratorFacade;
import openase.audiosearch.AudioSearchFacade;
import openase.audiosearch.AudioSearchProperties;
import openase.audiosearch.comm.request.AudioSearch;
import openase.audiosearch.comm.response.Response;
import openase.audiosearch.comm.response.SearchResult;
import openase.audiosearch.ranking.AudioRanking;
import openase.audiosearch.ranking.LongestIncreasingSequenceOfMatchesRankingStrategy;
import openase.audiosearch.ranking.MatchesCountRankingStrategy;
import openase.audiosearch.ranking.RankingStrategy;
import openase.audiosearch.ranking.SameDeltaOffsetsOfMatchesRankingStrategy;
import openase.audiosearch.ranking.UniqueQueryMatchesRankingStrategy;
import openase.audiosearch.ranking.UniqueRepositoryMatchesRankingStrategy;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;


class AudioSearchRequestProcessor {

	private static final Log logger = LogFactory.getLog(AudioSearchRequestProcessor.class);

	public static Response process(AudioSearch request) {
		final byte[] tdAudio = request.getAudioInput();
		final int maxResults = request.getMaxResults();

		logger.info("Starting to generate fingerprints for request");
		long ini_fp = now();
		final AudioFingerprint[] fps = FingerprintGeneratorFacade.generateFingerprints(tdAudio, AudioSearchProperties.CHUNK_SIZE);
		long end_fp = now();
		logger.info("Generate fingerprints for request took " + (end_fp - ini_fp) + "ms");

		final RankingStrategy[] strategies = getStrategies();

		final AudioRanking[] ranks;
		try {
			logger.info("Starting to search fingerprints for request");
			long ini_search = now();
			ranks = AudioSearchFacade.search(fps, strategies);
			long end_search = now();
			logger.info("Search of fingerprints for request took " + (end_search - ini_search) + "ms");
		} catch (StorageException se) {
			logger.error("Error searching fingerprints for request: " + se.getMessage(), se);
			throw new RuntimeException(se);
		}

		logger.info("Starting to rank found matches for request");
		long ini_rank = now();
		final String LF = System.getProperty("line.separator");
		StringBuilder sbResult = new StringBuilder();

		for (int i = 0; i < ranks.length; i++) {
			RankingStrategy rs = strategies[i];
			AudioRanking rank = ranks[i];

			sbResult.append(rs.getClass().getSimpleName()).append(LF);
			sbResult.append(LF);

			sbResult.append(rank.toString(maxResults));

			sbResult.append(LF);
		}
		long end_rank = now();
		logger.info("Ranking of matches for request took " + (end_rank - ini_rank) + "ms");

		return new SearchResult(sbResult.toString());
	}

	private static RankingStrategy[] getStrategies() {
		return new RankingStrategy[] { new MatchesCountRankingStrategy(), new UniqueRepositoryMatchesRankingStrategy(), new UniqueQueryMatchesRankingStrategy(), new LongestIncreasingSequenceOfMatchesRankingStrategy(), new SameDeltaOffsetsOfMatchesRankingStrategy() };
	}
	
	private static long now() {
		return System.currentTimeMillis();
	}

}
